use crate::performance::service::EchoTestRouterFactory;
use crate::performance::service::{EchoTestService, EchoTestServiceImpl};
use crate::EchoRouterFactory;
use std::time::{Duration, Instant};
use tokio::sync::oneshot;
use log::info;
use rpc::{DefaultLocalSeqCreator, RpcResult};
use rpc::bootstrap::BootstrapBuilder;
use rpc_client::client::RpcClientBuilder;
use rpc_derive::{router, service};
use rpc_server::server::RpcServerBuilder;

#[tokio::test(flavor = "multi_thread", worker_threads = 12)]
async fn test1() {
    many_test(8081, "bin-code", 10000, 15).await.unwrap();
}

async fn many_test(port: u32, codec_type: &'static str, num: u32, thread_num: u32) -> RpcResult<()>{
    tokio::spawn(async move {
        let bootstrap = BootstrapBuilder::new()
            .router("/echo", router!(echo_test))
            ;
        let _ = RpcServerBuilder::new(bootstrap, port)
            .build().start_server().await;
    });

    let now = Instant::now();
    let mut join = Vec::with_capacity(thread_num as usize);
    for k in 0..thread_num {
        let (oneshot_sender, oneshot_receiver) = oneshot::channel::<bool>();
        join.push(oneshot_receiver);
        tokio::spawn(async move {
            let bootstrap = BootstrapBuilder::new()
                .router("/echo", router!(echo))
                .build();
            let address = format!("127.0.0.1:{}", port);
            let client = RpcClientBuilder::new(bootstrap, &address)
                .set_current_codec_type(codec_type)
                .build();
            let mut channel = client.connection().await.unwrap();

            let mut echo_service = service!(channel.context.clone(), EchoTestService);

            for i in 0..num {
                let result = echo_service.echo(&mut channel, i as i32).await.unwrap();
                assert_eq!(result, (i+100) as i32);
            }
            oneshot_sender.send(true).unwrap();
        });
    }

    for t in join {
        t.await.unwrap();
    }
    let time = now.elapsed();
    println!("result:::::::::::::::: time: {}", time.as_millis());

    tokio::time::sleep(Duration::from_millis(100)).await;
    Ok(())
}

#[tokio::test]
async fn simple_test() {
    simple_build_test(8091, "bin-code", 10000).await;
}

async fn simple_build_test(port: u32, codec_type: &'static str, num: u32) {
    tokio::spawn(async move {
        let bootstrap = BootstrapBuilder::new()
            .router("/echo", router!(echo_test))
            ;
        let _ = RpcServerBuilder::new(bootstrap, port)
            .build().start_server().await;
    });

    let now = Instant::now();
    let bootstrap = BootstrapBuilder::new().build();
    let address = format!("127.0.0.1:{}", port);
    let client = RpcClientBuilder::new(bootstrap, &address)
        .set_current_codec_type(codec_type)
        .build();
    let mut channel = client.connection().await.unwrap();

    let mut echo_service = service!(channel.context.clone(), EchoTestService);

    for i in 0..num {
        let result = echo_service.echo(&mut channel, i as i32).await.unwrap();
        assert_eq!(result, (i+100) as i32);
    }

    let time = now.elapsed();
    println!("result:::::::::::::::: time: {}", time.as_millis());

    tokio::time::sleep(Duration::from_millis(100)).await;
}


// #[tokio::test]
async fn client_test() {
    client_business_test(8888, "json", 10000).await
}

async fn client_business_test(port: u32, codec_type: &'static str, num: u32) {
    let now = Instant::now();
    let bootstrap = BootstrapBuilder::new().build();
    let mut channel = RpcClientBuilder::new(bootstrap, &format!("127.0.0.1:{}", port))
        .set_current_codec_type(codec_type)
        .build().connection().await.unwrap();

    let mut echo_service = service!(channel.context.clone(), EchoTestService);
    for i in 0..num {
        let result = echo_service.echo(&mut channel, i as i32).await.unwrap();
        assert_eq!(result, (i+100) as i32);
    }

    info!("client test total time: {:?}", now.elapsed());
}
